// Copyright 2003 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Dan Egnor (egnor@google.com)
//
// A "smart" pointer type with reference tracking.  Every pointer to a
// particular object is kept on a circular linked list.  When the last pointer
// to an object is destroyed or reassigned, the object is deleted.
//
// Used properly, this deletes the object when the last reference goes away.
// There are several caveats:
// - Like all reference counting schemes, cycles lead to leaks.
// - Each smart pointer is actually two pointers (8 bytes instead of 4).
// - Every time a pointer is assigned, the entire list of pointers to that
//   object is traversed.  This class is therefore NOT SUITABLE when there
//   will often be more than two or three pointers to a particular object.
// - References are only tracked as long as linked_ptr<> objects are copied.
//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
//   will happen (double deletion).
//
// A good use of this class is storing object references in STL containers.
// You can safely put linked_ptr<> in a vector<>.
// Other uses may not be as good.
//
// Note: If you use an incomplete type with linked_ptr<>, the class
// *containing* linked_ptr<> must have a constructor and destructor (even
// if they do nothing!).
//
// Bill Gibbons suggested we use something like this.
//
// Thread Safety:
//   Unlike other linked_ptr implementations, in this implementation
//   a linked_ptr object is thread-safe in the sense that:
//     - it's safe to copy linked_ptr objects concurrently,
//     - it's safe to copy *from* a linked_ptr and read its underlying
//       raw pointer (e.g. via get()) concurrently, and
//     - it's safe to write to two linked_ptrs that point to the same
//       shared object concurrently.
// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
// confusion with normal linked_ptr.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_

#include <stdlib.h>
#include <assert.h>

#include "gtest/internal/gtest-port.h"

namespace testing
{
	namespace internal
	{

		// Protects copying of all linked_ptr objects.
		GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);

		// This is used internally by all instances of linked_ptr<>.  It needs to be
		// a non-template class because different types of linked_ptr<> can refer to
		// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
		// So, it needs to be possible for different types of linked_ptr to participate
		// in the same circular linked list, so we need a single class type here.
		//
		// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
		class linked_ptr_internal
		{
		public:
			// Create a new circle that includes only this instance.
			void join_new()
			{
				next_ = this;
			}

			// Many linked_ptr operations may change p.link_ for some linked_ptr
			// variable p in the same circle as this object.  Therefore we need
			// to prevent two such operations from occurring concurrently.
			//
			// Note that different types of linked_ptr objects can coexist in a
			// circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
			// linked_ptr<Derived2>).  Therefore we must use a single mutex to
			// protect all linked_ptr objects.  This can create serious
			// contention in production code, but is acceptable in a testing
			// framework.

			// Join an existing circle.
			void join(linked_ptr_internal const *ptr)
			GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex)
			{
				MutexLock lock(&g_linked_ptr_mutex);

				linked_ptr_internal const *p = ptr;
				while (p->next_ != ptr) p = p->next_;
				p->next_ = this;
				next_ = ptr;
			}

			// Leave whatever circle we're part of.  Returns true if we were the
			// last member of the circle.  Once this is done, you can join() another.
			bool depart()
			GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex)
			{
				MutexLock lock(&g_linked_ptr_mutex);

				if (next_ == this) return true;
				linked_ptr_internal const *p = next_;
				while (p->next_ != this) p = p->next_;
				p->next_ = next_;
				return false;
			}

		private:
			mutable linked_ptr_internal const *next_;
		};

		template <typename T>
		class linked_ptr
		{
		public:
			typedef T element_type;

			// Take over ownership of a raw pointer.  This should happen as soon as
			// possible after the object is created.
			explicit linked_ptr(T *ptr = NULL)
			{
				capture(ptr);
			}
			~linked_ptr()
			{
				depart();
			}

			// Copy an existing linked_ptr<>, adding ourselves to the list of references.
			template <typename U> linked_ptr(linked_ptr<U> const &ptr)
			{
				copy(&ptr);
			}
			linked_ptr(linked_ptr const &ptr)    // NOLINT
			{
				assert(&ptr != this);
				copy(&ptr);
			}

			// Assignment releases the old value and acquires the new.
			template <typename U> linked_ptr &operator=(linked_ptr<U> const &ptr)
			{
				depart();
				copy(&ptr);
				return *this;
			}

			linked_ptr &operator=(linked_ptr const &ptr)
			{
				if (&ptr != this)
				{
					depart();
					copy(&ptr);
				}
				return *this;
			}

			// Smart pointer members.
			void reset(T *ptr = NULL)
			{
				depart();
				capture(ptr);
			}
			T *get() const
			{
				return value_;
			}
			T *operator->() const
			{
				return value_;
			}
			T &operator*() const
			{
				return *value_;
			}

			bool operator==(T *p) const
			{
				return value_ == p;
			}
			bool operator!=(T *p) const
			{
				return value_ != p;
			}
			template <typename U>
			bool operator==(linked_ptr<U> const &ptr) const
			{
				return value_ == ptr.get();
			}
			template <typename U>
			bool operator!=(linked_ptr<U> const &ptr) const
			{
				return value_ != ptr.get();
			}

		private:
			template <typename U>
			friend class linked_ptr;

			T *value_;
			linked_ptr_internal link_;

			void depart()
			{
				if (link_.depart()) delete value_;
			}

			void capture(T *ptr)
			{
				value_ = ptr;
				link_.join_new();
			}

			template <typename U> void copy(linked_ptr<U> const *ptr)
			{
				value_ = ptr->get();
				if (value_)
					link_.join(&ptr->link_);
				else
					link_.join_new();
			}
		};

		template<typename T> inline
		bool operator==(T *ptr, const linked_ptr<T> &x)
		{
			return ptr == x.get();
		}

		template<typename T> inline
		bool operator!=(T *ptr, const linked_ptr<T> &x)
		{
			return ptr != x.get();
		}

		// A function to convert T* into linked_ptr<T>
		// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
		// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
		template <typename T>
		linked_ptr<T> make_linked_ptr(T *ptr)
		{
			return linked_ptr<T>(ptr);
		}

	}  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
